package process

import (
	"fmt"
	process2 "github.com/shirou/gopsutil/process"
	"io"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"pm/config"
	"pm/model"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const (
	logSuffix = ".log"
	ErrorLogType = "error"
	InfoLogType = "info"
)

var processData *Process2

type Process2 struct {
	 processList []*model.Process
}

func NewProcess2() *Process2{
	if processData != nil{
		return processData
	}
	processData = &Process2{
		make([]*model.Process, 0),
	}
	go processData.registerQuilt()
	return processData
}



func (p *Process2)registerQuilt(){
	signalChan := make(chan os.Signal,1)
	signal.Notify(signalChan, os.Interrupt, _sigINT, _sigTERM)
	fmt.Println("i am workding!")
	<-signalChan
	for _,item := range p.processList{
		item.Pointer.Process.Kill()
	}
	os.Exit(0)
}



func (p *Process2)GetProcess(key string)*model.Process{
	id := -1
	if val,err := strconv.Atoi(key);err ==nil{
		id = val
	}

	for k,item:= range p.processList {
		if id == k || item.Name == key{
			SetProcessInfo(item)
			return item
		}
	}

	return nil
}

func (p *Process2)GetAllProcess()[]*model.Process{
	for _, p:= range p.processList {
		SetProcessInfo(p)
	}
	return p.processList
}

//设置进程cpu、内存信息
func SetProcessInfo(p *model.Process){
	pinfo,_ := process2.NewProcess(int32(p.Pid))
	if cpu, err := pinfo.CPUPercent();err == nil{
		p.Cpu = fmt.Sprintf("%.2f", cpu)
	}

	if mInfo, err := pinfo.MemoryInfo();err == nil{
		var memVal string
		if mInfo.RSS <= 1024 {
			memVal = fmt.Sprintf("%d", mInfo.RSS)
		} else if mInfo.RSS <= 1024*1024 {
			memVal = fmt.Sprintf("%d KB", mInfo.RSS/1024)
		} else if mInfo.RSS <= 1024*1024*1024 {
			memVal = fmt.Sprintf("%d MB", mInfo.RSS/(1024*1024))
		} else if mInfo.RSS <= 1024*1024*1024*1024 {
			memVal = fmt.Sprintf("%d GB", mInfo.RSS/(1024*1024*1024))
		} else {
			memVal = fmt.Sprintf("%d", mInfo.RSS)
		}
		p.Memory = memVal
	}
}

func (p *Process2)GetProcessByPath(path string)*model.Process{
	for _,item:= range p.processList {
		if item.ProcessFile == path{
			return item
		}
	}
	return nil
}


func (p *Process2)DelProcess(key string){
	id,_ := strconv.Atoi(key)

	for k,item:= range p.processList {
		if  id == k  || item.Name == key{
			if k < len(p.processList) -1{
				p.processList = append(p.processList[0:k],	p.processList[k+1:]...)
			}else{
				p.processList = p.processList[:k]
			}
			break
		}
	}
}



func GetLogPath(customLogFile string, hash string, logType string) (string, error) {
	if len(customLogFile) <= 0{
		customLogFile =  strings.TrimRight(config.ConfigData.Logs, "/") + "/" + hash +"."+logType + logSuffix
	}
	dir := filepath.Dir(customLogFile)
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			return "", err
		}
	}
	return customLogFile, nil
}

type LogOutput struct {
	io.Writer
	io.Closer
	logType string
	logFile *os.File
	process *model.Process
}



func (l * LogOutput)Write(p []byte)(int,error){
	logStr := time.Now().UTC().Format("2006-01-02 15:04:05") + " " + string(p)
	l.checkFile()
	l.logFile.WriteString(logStr)
	return len(p),nil
}

func (l * LogOutput)checkFile(){
	 fileInfo,_ := l.logFile.Stat()
	var  maxFileSize  int64 = 1024 * 1024 * 100
	 if l.logType == ErrorLogType{
		 maxFileSize = 1024 * 1024 * 20
	 }
	 fileName := fileInfo.Name()
	 baseName := filepath.Base(fileName)
	 nameArr := strings.Split(baseName, "-")
	 fileDay := nameArr[len(nameArr) - 4]
	fileDayNum, _ := strconv.Atoi(fileDay)
	 nowDay := time.Now().UTC().Day()
	 if fileInfo.Size() >= maxFileSize || fileDayNum !=  nowDay{
		 logName := l.process.Name + time.Now().UTC().Format("2006-01-02-15-04-05")
		 logFilePath,err := GetLogPath("", logName, l.logType)
		 if err != nil{
			 log.Println(l.process.Name ,  "日志文件获取失败-", err.Error())
			 return
		 }
		 file, err1 := os.OpenFile(logFilePath, syscall.O_CREAT|syscall.O_APPEND|syscall.O_WRONLY, 0755)
		 if err1 != nil {
			 log.Println(logFilePath,  "日志文件打开失败-", err1.Error())
			 return
		 }
		 l.logFile.Close()

		 if l.logType == ErrorLogType{
			 l.process.ErrorLog = logFilePath
		 }else{
			 l.process.Log = logFilePath
		 }
		 l.logFile = file
	 }
}

func (l * LogOutput)Close()error{
	return l.logFile.Close()
}





func NewLogOutput(logFile, logType string, process *model.Process)*LogOutput{
	logName := process.Name + time.Now().UTC().Format("2006-01-02-15-04-05")
	logFilePath,err := GetLogPath(logFile, logName, logType)
	if err != nil{
		log.Println(process.Name ,  "日志文件获取失败-", err.Error())
		return nil
	}
	file, err1 := os.OpenFile(logFilePath, syscall.O_CREAT|syscall.O_APPEND|syscall.O_WRONLY, 0755)
	if err1 != nil {
		log.Println(logFilePath,  "日志文件打开失败-", err.Error())
		return nil
	}
	if logType == ErrorLogType{
		process.ErrorLog = logFilePath
	}else{
		process.Log = logFilePath
	}
	return &LogOutput{logFile:file, process: process,logType:logType }
}





